/*
 * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
 * Copyright (c) 1996 by Silicon Graphics.  All rights reserved.
 * Copyright (c) 1998 by Fergus Henderson.  All rights reserved.
 * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
 * All rights reserved.
 * Copyright (c) 2008-2025 Ivan Maidanski
 *
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 *
 * Permission is hereby granted to use or copy this program
 * for any purpose, provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 */

/*
 * This should never be included directly; it is included only from
 * `gc.h` file.  We separate it only to make `gc.h` file more suitable
 * as documentation.
 */
#if defined(GC_H)

/* Convenient internal macro to test version of gcc. */
#  if defined(__GNUC__) && defined(__GNUC_MINOR__)
#    define GC_GNUC_PREREQ(major, minor) \
      ((__GNUC__ << 8) + __GNUC_MINOR__ >= ((major) << 8) + (minor))
#  else
#    define GC_GNUC_PREREQ(major, minor) 0 /*< false */
#  endif

/*
 * A macro to define integer types of a pointer size.  There seems to
 * be no way to do this even semi-portably.  The following is probably
 * no better/worse than almost anything else.
 * The ANSI standard suggests that `size_t` and `ptrdiff_t` might be
 * better choices.  But those had incorrect definitions on some older
 * systems; notably `typedef int size_t` is wrong.
 */
#  ifdef _WIN64
#    if defined(__int64) && !defined(CPPCHECK)
#      define GC_SIGNEDWORD __int64
#    else
#      define GC_SIGNEDWORD long long
#    endif
#  else
#    define GC_SIGNEDWORD long
#  endif
#  define GC_UNSIGNEDWORD unsigned GC_SIGNEDWORD

/* Size of a pointer in bytes. */
#  if defined(__SIZEOF_POINTER__)
#    define GC_SIZEOF_PTR __SIZEOF_POINTER__
#  elif defined(__LP64__) || defined(_LP64) || defined(_WIN64)               \
      || defined(__alpha__) || defined(__arch64__) || defined(__powerpc64__) \
      || defined(__s390x__) || defined(__sparcv9)                            \
      || (defined(__x86_64__) && !defined(__ILP32__))
#    define GC_SIZEOF_PTR 8
#  else
#    define GC_SIZEOF_PTR 4
#  endif

/*
 * The return type of `GC_get_version()`.  A 32-bit unsigned integer
 * or longer.
 */
#  define GC_VERSION_VAL_T unsigned

/*
 * Some tests for old macros.  These violate our namespace rules and
 * are deprecated.  Use the `GC_` names instead.
 */
#  if defined(SOLARIS_THREADS) || defined(_SOLARIS_THREADS) \
      || defined(_SOLARIS_PTHREADS) || defined(GC_SOLARIS_PTHREADS)
/*
 * We no longer support old style Solaris threads.
 * `GC_SOLARIS_THREADS` now means `pthreads`.
 */
#    ifndef GC_SOLARIS_THREADS
#      define GC_SOLARIS_THREADS
#    endif
#  endif
#  if defined(IRIX_THREADS)
#    define GC_IRIX_THREADS
#  endif
#  if defined(DGUX_THREADS) && !defined(GC_DGUX386_THREADS)
#    define GC_DGUX386_THREADS
#  endif
#  if defined(AIX_THREADS)
#    define GC_AIX_THREADS
#  endif
#  if defined(HPUX_THREADS)
#    define GC_HPUX_THREADS
#  endif
#  if defined(OSF1_THREADS)
#    define GC_OSF1_THREADS
#  endif
#  if defined(LINUX_THREADS)
#    define GC_LINUX_THREADS
#  endif
#  if defined(WIN32_THREADS)
#    define GC_WIN32_THREADS
#  endif
#  if defined(RTEMS_THREADS)
#    define GC_RTEMS_PTHREADS
#  endif
#  if defined(USE_LD_WRAP)
#    define GC_USE_LD_WRAP
#  endif

#  if defined(GC_WIN32_PTHREADS) && !defined(GC_WIN32_THREADS)
/* Using pthreads-win32 library (or other Win32 implementation). */
#    define GC_WIN32_THREADS
#  endif

#  if defined(GC_AIX_THREADS) || defined(GC_DARWIN_THREADS)         \
      || defined(GC_DGUX386_THREADS) || defined(GC_FREEBSD_THREADS) \
      || defined(GC_HPUX_THREADS) || defined(GC_IRIX_THREADS)       \
      || defined(GC_LINUX_THREADS) || defined(GC_NETBSD_THREADS)    \
      || defined(GC_OPENBSD_THREADS) || defined(GC_OSF1_THREADS)    \
      || defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS)   \
      || defined(GC_RTEMS_PTHREADS)
#    ifndef GC_THREADS
#      define GC_THREADS
#    endif
#  elif defined(GC_THREADS)
#    if defined(__linux__) || defined(__native_client__)
#      define GC_LINUX_THREADS
#    elif defined(__OpenBSD__)
#      define GC_OPENBSD_THREADS
#    elif defined(_PA_RISC1_1) || defined(_PA_RISC2_0) || defined(hppa) \
        || defined(__HPPA) || (defined(__ia64) && defined(_HPUX_SOURCE))
#      define GC_HPUX_THREADS
#    elif defined(__HAIKU__)
#      define GC_HAIKU_THREADS
#    elif (defined(__DragonFly__) || defined(__FreeBSD_kernel__) \
           || defined(__FreeBSD__))                              \
        && !defined(GC_NO_FREEBSD)
#      define GC_FREEBSD_THREADS
#    elif defined(__NetBSD__)
#      define GC_NETBSD_THREADS
#    elif defined(__alpha) || defined(__alpha__) /*< not Linux, not xBSD */
#      define GC_OSF1_THREADS
#    elif (defined(mips) || defined(__mips) || defined(_mips))        \
        && !(defined(nec_ews) || defined(_nec_ews) || defined(ultrix) \
             || defined(__ultrix))
#      define GC_IRIX_THREADS
#    elif defined(__sparc) /* `&& !defined(__linux__)` */              \
        || ((defined(sun) || defined(__sun))                           \
            && (defined(i386) || defined(__i386__) || defined(__amd64) \
                || defined(__amd64__)))
#      define GC_SOLARIS_THREADS
#    elif defined(__APPLE__) && defined(__MACH__)
#      define GC_DARWIN_THREADS
#    endif
#    if defined(DGUX) && (defined(i386) || defined(__i386__))
#      define GC_DGUX386_THREADS
#    endif
#    if defined(_AIX)
#      define GC_AIX_THREADS
#    endif
#    if (defined(_WIN32) || defined(_MSC_VER) || defined(__BORLANDC__) \
         || defined(__CYGWIN32__) || defined(__CYGWIN__)               \
         || defined(__CEGCC__) || defined(_WIN32_WCE)                  \
         || defined(__MINGW32__))                                      \
        && !defined(GC_WIN32_THREADS)
/* Either POSIX or native Win32 threads. */
#      define GC_WIN32_THREADS
#    endif
#    if defined(__rtems__) && (defined(i386) || defined(__i386__))
#      define GC_RTEMS_PTHREADS
#    endif
#  endif /* GC_THREADS */

#  undef GC_PTHREADS
#  if (!defined(GC_WIN32_THREADS) || defined(GC_WIN32_PTHREADS) \
       || defined(__CYGWIN32__) || defined(__CYGWIN__))         \
      && defined(GC_THREADS) && !defined(NN_PLATFORM_CTR)       \
      && !defined(NN_BUILD_TARGET_PLATFORM_NX)
/* POSIX threads (`pthreads`). */
#    define GC_PTHREADS
#  endif

#  if !defined(_PTHREADS) && defined(GC_NETBSD_THREADS)
#    define _PTHREADS
#  endif

#  if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
#    define _POSIX4A_DRAFT10_SOURCE 1
#  endif

#  if !defined(_REENTRANT) && defined(GC_PTHREADS) \
      && !defined(GC_WIN32_THREADS)
/*
 * Better late than never.  This fails if system headers that depend
 * on this were previously included.
 */
#    define _REENTRANT 1
#  endif

#  if defined(__clang__) && defined(__CYGWIN__) && defined(GC_THREADS) \
      && defined(__LP64__)
/*
 * Workaround "__stdcall__ ignored for this target" clang warning.
 * Note: `__stdcall` is defined implicitly based on `__stdcall__`.
 */
#    define __stdcall__ /*< empty */
#  endif

#  define __GC
#  if !defined(_WIN32_WCE) || defined(__GNUC__)
#    include <stddef.h>
#    if defined(__MINGW32__) && !defined(_WIN32_WCE) \
        || defined(__CHERI_PURE_CAPABILITY__)
#      include <stdint.h>
/*
 * We mention `uintptr_t`.  Perhaps this should be included in pure
 * MS environments as well.
 */
#    endif
#  else
/* Yet more kludges for WinCE. */
#    include <stdlib.h> /*< for `size_t` */
#    ifndef _PTRDIFF_T_DEFINED
/* `ptrdiff_t` is not defined. */
#      define _PTRDIFF_T_DEFINED
typedef long ptrdiff_t;
#    endif
#  endif /* _WIN32_WCE */

#  if !defined(GC_NOT_DLL) && !defined(GC_DLL)  \
      && ((defined(_DLL) && !defined(__GNUC__)) \
          || (defined(DLL_EXPORT) && defined(GC_BUILD)))
#    define GC_DLL
#  endif

#  if defined(GC_DLL) && !defined(GC_API)

#    if defined(__CEGCC__)
#      if defined(GC_BUILD)
#        define GC_API __declspec(dllexport)
#      else
#        define GC_API __declspec(dllimport)
#      endif

#    elif defined(__MINGW32__)
#      if defined(__cplusplus) && defined(GC_BUILD)
#        define GC_API extern __declspec(dllexport)
#      elif defined(GC_BUILD) || defined(__MINGW32_DELAY_LOAD__)
#        define GC_API __declspec(dllexport)
#      else
#        define GC_API extern __declspec(dllimport)
#      endif

#    elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
        || defined(__CYGWIN__)
#      ifdef GC_BUILD
#        define GC_API extern __declspec(dllexport)
#      else
#        define GC_API __declspec(dllimport)
#      endif

#    elif defined(__WATCOMC__)
#      ifdef GC_BUILD
#        define GC_API extern __declspec(dllexport)
#      else
#        define GC_API extern __declspec(dllimport)
#      endif

#    elif defined(__SYMBIAN32__)
#      ifdef GC_BUILD
#        define GC_API extern EXPORT_C
#      else
#        define GC_API extern IMPORT_C
#      endif

#    elif defined(__GNUC__)
/* Only matters if used in conjunction with `-fvisibility=hidden` option. */
#      if defined(GC_BUILD) && !defined(GC_NO_VISIBILITY) \
          && (GC_GNUC_PREREQ(4, 0) || defined(GC_VISIBILITY_HIDDEN_SET))
#        define GC_API extern __attribute__((__visibility__("default")))
#      endif
#    endif
#  endif /* GC_DLL */

#  ifndef GC_API
#    define GC_API extern
#  endif

#  ifndef GC_CALL
#    define GC_CALL
#  endif

#  ifndef GC_CALLBACK
#    define GC_CALLBACK GC_CALL
#  endif

#  ifndef GC_ATTR_MALLOC
/*
 * `malloc` attribute should be used for all `malloc`-like functions
 * (to tell the compiler that a function may be treated as if any
 * non-`NULL` pointer it returns cannot alias any other pointer valid
 * when the function returns).  If the client code violates this rule
 * by using custom `GC_oom_func`, then the client should define
 * `GC_OOM_FUNC_RETURNS_ALIAS` macro.
 */
#    ifdef GC_OOM_FUNC_RETURNS_ALIAS
#      define GC_ATTR_MALLOC /*< empty */
#    elif GC_GNUC_PREREQ(3, 1)
#      define GC_ATTR_MALLOC __attribute__((__malloc__))
#    elif defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(__EDG__)
#      define GC_ATTR_MALLOC \
        __declspec(allocator) __declspec(noalias) __declspec(restrict)
#    elif defined(_MSC_VER) && _MSC_VER >= 1400
#      define GC_ATTR_MALLOC __declspec(noalias) __declspec(restrict)
#    else
#      define GC_ATTR_MALLOC
#    endif
#  endif

#  ifndef GC_ATTR_ALLOC_SIZE
/* `alloc_size` attribute improves `__builtin_object_size` correctness. */
#    undef GC_ATTR_CALLOC_SIZE
#    ifdef __clang__
#      if __has_attribute(__alloc_size__)
#        define GC_ATTR_ALLOC_SIZE(argnum) \
          __attribute__((__alloc_size__(argnum)))
#        define GC_ATTR_CALLOC_SIZE(n, s) __attribute__((__alloc_size__(n, s)))
#      else
#        define GC_ATTR_ALLOC_SIZE(argnum) /*< empty */
#      endif
#    elif GC_GNUC_PREREQ(4, 3) && !defined(__ICC)
#      define GC_ATTR_ALLOC_SIZE(argnum) \
        __attribute__((__alloc_size__(argnum)))
#      define GC_ATTR_CALLOC_SIZE(n, s) __attribute__((__alloc_size__(n, s)))
#    else
#      define GC_ATTR_ALLOC_SIZE(argnum) /*< empty */
#    endif
#  endif

#  ifndef GC_ATTR_CALLOC_SIZE
#    define GC_ATTR_CALLOC_SIZE(n, s) /*< empty */
#  endif

#  ifndef GC_ATTR_NONNULL
#    if GC_GNUC_PREREQ(4, 0)
#      define GC_ATTR_NONNULL(argnum) __attribute__((__nonnull__(argnum)))
#    else
#      define GC_ATTR_NONNULL(argnum) /*< empty */
#    endif
#  endif

#  ifndef GC_ATTR_CONST
#    if GC_GNUC_PREREQ(4, 0)
#      define GC_ATTR_CONST __attribute__((__const__))
#    else
#      define GC_ATTR_CONST /*< empty */
#    endif
#  endif

#  ifndef GC_ATTR_DEPRECATED
#    ifdef GC_BUILD
#      undef GC_ATTR_DEPRECATED
#      define GC_ATTR_DEPRECATED /*< empty */
#    elif GC_GNUC_PREREQ(4, 0)
#      define GC_ATTR_DEPRECATED __attribute__((__deprecated__))
#    elif defined(_MSC_VER) && _MSC_VER >= 1200
#      define GC_ATTR_DEPRECATED __declspec(deprecated)
#    else
#      define GC_ATTR_DEPRECATED /*< empty */
#    endif
#  endif

#  ifndef GC_ATTR_NORETURN
#    if GC_GNUC_PREREQ(2, 7)
#      define GC_ATTR_NORETURN __attribute__((__noreturn__))
#    elif defined(_MSC_VER) && _MSC_VER >= 1310 /*< VS 2003+ */
#      define GC_ATTR_NORETURN __declspec(noreturn)
#    elif defined(__NORETURN) /*< used in Solaris */
#      define GC_ATTR_NORETURN __NORETURN
#    else
#      define GC_ATTR_NORETURN /*< empty */
#    endif
#  endif

#  if defined(__sgi) && !defined(__GNUC__) && _COMPILER_VERSION >= 720
#    define GC_ADD_CALLER
#    define GC_RETURN_ADDR ((GC_return_addr_t)__return_address)
#  endif

#  if defined(__linux__) || defined(__GLIBC__)
#    if !defined(__native_client__)
#      include <features.h>
#    endif
#    if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \
        && !defined(__ia64__) && !defined(GC_MISSING_EXECINFO_H)  \
        && !defined(GC_HAVE_BUILTIN_BACKTRACE)
#      define GC_HAVE_BUILTIN_BACKTRACE
#    endif
#    if defined(__i386__) || defined(__amd64__) || defined(__x86_64__)
#      define GC_CAN_SAVE_CALL_STACKS
#    endif
#  endif /* GLIBC */

#  if defined(_MSC_VER) && (_MSC_VER >= 1200 /* v12.0+ (MSVC 6.0+) */) \
      && !defined(_M_ARM) && !defined(_M_ARM64) && !defined(_AMD64_)   \
      && !defined(_M_X64) && !defined(_WIN32_WCE)                      \
      && !defined(GC_HAVE_NO_BUILTIN_BACKTRACE)                        \
      && !defined(GC_HAVE_BUILTIN_BACKTRACE)
#    define GC_HAVE_BUILTIN_BACKTRACE
#  endif

#  if defined(GC_HAVE_BUILTIN_BACKTRACE) && !defined(GC_CAN_SAVE_CALL_STACKS) \
      || defined(__sparc)
#    define GC_CAN_SAVE_CALL_STACKS
#  endif

/*
 * If we are on a platform on which we cannot save call stacks, but
 * gcc is normally used, we go ahead and define `GC_ADD_CALLER` macro.
 * We make this decision independent of whether gcc is actually being
 * used, in order to keep the interface consistent, and allow mixing
 * of compilers.
 * This may also be desirable if it is possible but expensive to
 * retrieve the call chain.
 */
#  if (defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) \
       || defined(__FreeBSD_kernel__) || defined(__HAIKU__)                 \
       || defined(__NetBSD__) || defined(__OpenBSD__)                       \
       || defined(HOST_ANDROID) || defined(__ANDROID__))                    \
      && !defined(GC_CAN_SAVE_CALL_STACKS)
#    define GC_ADD_CALLER
#    if GC_GNUC_PREREQ(2, 95)
/*
 * gcc knows how to retrieve return address, but we do not know how to
 * generate call stacks.
 */
#      define GC_RETURN_ADDR ((GC_return_addr_t)__builtin_return_address(0))
#      if GC_GNUC_PREREQ(4, 0)                                     \
          && (defined(__i386__) || defined(__amd64__)              \
              || defined(__x86_64__) /* and probably others... */) \
          && !defined(GC_NO_RETURN_ADDR_PARENT)
#        define GC_HAVE_RETURN_ADDR_PARENT
#        define GC_RETURN_ADDR_PARENT                       \
          ((GC_return_addr_t)__builtin_extract_return_addr( \
              __builtin_return_address(1)))
/*
 * Note: a compiler might complain that calling `__builtin_return_address`
 * with a nonzero argument is unsafe.
 */
#      endif
#    else
/* Just pass 0 for gcc compatibility. */
#      define GC_RETURN_ADDR ((GC_return_addr_t)0)
#    endif
#  endif /* !GC_CAN_SAVE_CALL_STACKS */

#  ifdef GC_PTHREADS

#    if (defined(GC_DARWIN_THREADS) || defined(GC_WIN32_PTHREADS)     \
         || defined(__native_client__) || defined(GC_RTEMS_PTHREADS)) \
        && !defined(GC_NO_DLOPEN)
/* Either there is no `dlopen()` or we do not need to intercept it. */
#      define GC_NO_DLOPEN
#    endif

#    if (defined(GC_DARWIN_THREADS) || defined(GC_WIN32_PTHREADS) \
         || defined(__native_client__))                           \
        && !defined(GC_NO_PTHREAD_SIGMASK)
/* Either there is no `pthread_sigmask()` or no need to intercept it. */
#      define GC_NO_PTHREAD_SIGMASK
#    endif

#    if defined(__native_client__)
/*
 * At present, NaCl `pthread_create()` prototype does not have
 * `const` for its `attr` argument; also, NaCl `pthread_exit()` one
 * does not have `noreturn` attribute.
 */
#      ifndef GC_PTHREAD_CREATE_CONST
#        define GC_PTHREAD_CREATE_CONST /*< empty */
#      endif
#      ifndef GC_HAVE_PTHREAD_EXIT
#        define GC_HAVE_PTHREAD_EXIT
#        define GC_PTHREAD_EXIT_ATTRIBUTE /*< empty */
#      endif
#    endif

#    if !defined(GC_HAVE_PTHREAD_EXIT)                           \
        && ((defined(GC_LINUX_THREADS) && !defined(HOST_ANDROID) \
             && !defined(__ANDROID__))                           \
            || defined(GC_SOLARIS_THREADS) || defined(__COSMOPOLITAN__))
/* Intercept `pthread_exit()` where available and needed. */
#      define GC_HAVE_PTHREAD_EXIT
#      define GC_PTHREAD_EXIT_ATTRIBUTE GC_ATTR_NORETURN
#    endif

#    if (!defined(GC_HAVE_PTHREAD_EXIT) || defined(__native_client__)) \
        && !defined(GC_NO_PTHREAD_CANCEL)
/* Either there is no `pthread_cancel()` or no need to intercept it. */
#      define GC_NO_PTHREAD_CANCEL
#    endif

#  endif /* GC_PTHREADS */

#  ifdef __cplusplus

#    ifndef GC_ATTR_EXPLICIT
#      if __cplusplus >= 201103L && !defined(__clang__) \
          || _MSVC_LANG >= 201103L || defined(CPPCHECK)
#        define GC_ATTR_EXPLICIT explicit
#      else
#        define GC_ATTR_EXPLICIT /*< empty */
#      endif
#    endif

#    ifndef GC_NOEXCEPT
#      if defined(__DMC__)                                  \
          || (defined(__BORLANDC__)                         \
              && (defined(_RWSTD_NO_EXCEPTIONS)             \
                  || defined(_RWSTD_NO_EX_SPEC)))           \
          || (defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) \
              && !_HAS_EXCEPTIONS)                          \
          || (defined(__WATCOMC__) && !defined(_CPPUNWIND))
#        define GC_NOEXCEPT /*< empty */
#        ifndef GC_NEW_ABORTS_ON_OOM
#          define GC_NEW_ABORTS_ON_OOM
#        endif
#      elif __cplusplus >= 201103L || _MSVC_LANG >= 201103L
#        define GC_NOEXCEPT noexcept
#      else
#        define GC_NOEXCEPT throw()
#      endif
#    endif

#    ifndef GC_CONSTEXPR
#      if __cplusplus >= 202002L
#        define GC_CONSTEXPR constexpr
#      else
#        define GC_CONSTEXPR /*< empty */
#      endif
#    endif

#  endif /* __cplusplus */

#endif
